grammar BitQV2;
@header {
	package com.xuanyue.db.xuan.antlr.v2;
}

@lexer::members{
	
	private int parallel = 1;
	
	java.util.regex.Pattern parallelReg = java.util.regex.Pattern.compile("parallel\\s*?\\(\\s*?(\\d+?)\\s*?\\)");
	java.util.regex.Pattern p = java.util.regex.Pattern.compile("/\\*(.*?)\\*/");
	public int getParallel(){
		return this.parallel;
	}
	void showme(){
		
		java.util.regex.Matcher m = p.matcher(this.getText());
		
		if(m.find()){
			
			java.util.regex.Matcher m2 = parallelReg.matcher(m.group(1));
			if(m2.find()) {
				parallel = Integer.parseInt(m2.group(1));
				if(parallel<1){
					parallel=1;
				}else if(parallel>20){
					parallel =20;
				}
			}
		}
		
		skip();
	}
}

@parser::members{
@Override
public Token match(int ttype) throws RecognitionException {
	Token t = getCurrentToken();
	if ( t.getType()==ttype ) {
		if ( ttype==Token.EOF ) {
			matchedEOF = true;
		}
		_errHandler.reportMatch(this);
		consume();
		return t;
	}
	else {
		throw new RuntimeException("miss "+ _SYMBOLIC_NAMES[ttype]);
	}
	
}
}

bitQ:query|insertInto|update|delete|alertTable|createTable;

fields: '('  NAME  (',' NAME)*   ')';

/** names */
fullName:NAME ('.'NAME)*;

/** where function */
phone_seach:Phone_seach '('  fullName  ','  op=(PositionMatch|Contains|Has_Every_Char)  ','STRING  ')';
orNot:OR NOT?;
andNot:AND NOT?;
orCondition : NOT? andCondition (operator=orNot  andCondition)*;
andCondition :     conditionElement (operator=andNot conditionElement)*;
conditionElement:  groupCondition|conditionExpr;
groupCondition:  '(' orCondition ')';
//conditionExpr : NAME op=('=' | '!='|'>='|'>'|'<='|'<'|Contains|PositionMatch) values|phone_seach|reuniteExpr;
boolTF: TRUE|FALSE;
values:to_date|STRING|NUM|boolTF|TransArrt|NULL;
to_date:TO_DATE '(' STRING COMMA STRING  ')';
/**
 * adapter list and map
 */
array: ARRAY_L values (',' values)*  ARRAY_R;
exprValue: values|array ;

arrayIndex0: NUM;
arrayIndex1: NUM COLON NUM;
arrayIndex2: NUM COLON;
arrayIndex3: COLON NUM;
arrayIndex4: COLON;
arrayIndex: arrayIndex0|arrayIndex1|arrayIndex2|arrayIndex3|arrayIndex4;
exprKey:arrayIndex|STRING;

function:FUNCTION '(' NAME (ARRAY_L exprKey ARRAY_R)? COMMA NAME (COMMA values)*  ')';
baseExpr:NAME (ARRAY_L exprKey ARRAY_R)? op=('=' | '!='|'>='|'>'|'<='|'<') exprValue;
conditionExpr:baseExpr|function;

/** DML-- select function */
query :  SELECT result FROM repo (WHERE orCondition)? sortBy? mix? limit? saveAsFile?  SEMI?;
result:NAME(','NAME)*;
repo: NAME;

/** order by function */
sortBy: Order By  sortE   (','sortE)*;
sortE: NAME (ARRAY_L exprKey ARRAY_R)? (DESC|ASC)?;
//groupBy:Group By fullName (Having function op=('=' | '!='|'>='|'>'|'<='|'<')  NUM)?;
//function: op=(Sum|Max|Min|Count|Avg) '(' (fullName|NUM)  ')';
mix:MIX fullName (ARRAY_L NUM  (','NUM)*  ARRAY_R)?;
/** page */
limit:LIMIT NUM(','NUM)?;
/** save data to file*/
saveAsFile: SAVE AS STRING;
/** DML --insert into  */
insertInto:INSERT INTO NAME fields?  VALUES '('  exprValue (',' exprValue )*    ')' SEMI?;

/** DML -- update */
setValue: NAME '=' values;
update:UPDATE NAME SET  setValue (',' setValue)* (WHERE orCondition)? SEMI?;
/** DML -- delete */
delete:DELETE FROM NAME (WHERE orCondition)? SEMI?;
///////////////////////////////////////////////////////////////////////
////////////////////////////DDL/////////////////////////////////////////

setSource:SET SOURCE'(' NUM ')';

createTable: CREATE TABLE NAME '(' column (COMMA column)*   ')' (COMMA setSource)?;
column: NAME cType;
cType:  
	intType|
	uintType|
	dateType|
	floatType|
	ufloatType|
	booleanType|
	longType|
	ulongType|
	phoneType|
	listType|
	mapType
	;
//numType:intType|
//	uintType|
//	dateType|
//	floatType|
//	ufloatType|
//	longType|
//	ulongType;

intType:INT'(' NUM ')';
uintType:UINT'(' NUM ')';
dateType:DATE;
floatType:FLOAT'(' NUM COMMA NUM (COMMA NUM)? ')';
ufloatType:UFLOAT'(' NUM COMMA NUM')';
booleanType:BOOLEAN;
longType:LONG'(' NUM (COMMA NUM)? ')';
ulongType:ULONG'(' NUM ')';
phoneType:PHONE;
listType:LIST'(' cType COMMA NUM ')';
mapType:  MAP'(' cType COMMA  NAME (COMMA NAME)*   ')';

alertTable:ALTER TABLE NAME alertOP;
alertOP:ADD column|DROP NAME|ALTER NAME column|setSource;

/////////////////////////////////////////////////////////////////////////////////////////////////////
/**query*/
SELECT : [Ss][Ee][Ll][Ee][Cc][Tt];

/** table */
FROM : [Ff][Rr][Oo][Mm];
ON:[Oo][Nn];
LEFT:[Ll][Ee][Ff][Tt];
RIGHT:[Rr][Ii][Gg][Hh][Tt];
JOIN:[Jj][Oo][Ii][Nn];

/** where */
WHERE : [Ww][Hh][Ee][Rr][Ee];
AND : [Aa][Nn][Dd];
OR : [Oo][Rr];
NOT : [Nn][Oo][Tt];
ExprNot:'!';
FUNCTION:[Ff][Uu][Nn][Cc][Tt][Ii][Oo][Nn];


/** order by */
Order:[Oo][Rr][Dd][Ee][Rr];
By:[Bb][Yy];
DESC:[Dd][Ee][Ss][Cc];
ASC:[Aa][Ss][Cc];
MIX:[Mm][Ii][Xx];

/** data type */
PLUS:'+';
REDUCE:'-';
STRING : '\'' ( ~('\''|'\\') | ('\\' .) )* '\''
         | '"' ( ~('"'|'\\') | ('\\' .) )* '"';
NUM: (PLUS|REDUCE)? '0'..'9'+(DOT '0'..'9'+ )?('l'|'f')?;

TRUE:[Tt][Rr][Uu][Ee];
FALSE:[Ff][Aa][Ll][Ss][Ee];
NULL:[Nn][Uu][Ll][Ll];
TO_DATE:[Tt][Oo]'_'[Dd][Aa][Tt][Ee];
/**  expr : value and function */
TransArrt:'?'[a-zA-Z_0-9]+;
Phone_seach:[Pp][Hh][Oo][Nn][Ee]'_'[Ss][Ee][Aa][Cc][Hh];
PositionMatch:[Pp][Oo][Ss][Ii][Tt][Ii][Oo][Nn][Mm][Aa][Tt][Cc][Hh];
Contains:[Cc][Oo][Nn][Tt][Aa][Ii][Nn][Ss];
Has_Every_Char:[Hh][Aa][Ss]'_'[Ee][Vv][Ee][Rr][Yy]'_'[Cc][Hh][Aa][Rr];
STARTSWITH:[Ss][Tt][Aa][Rr][Tt][Ss][Ww][Ii][Tt][Hh];
ENDSWITH:[Ee][Nn][Dd][Ss][Ww][Ii][Tt][Hh];

/** - insert into */
INSERT:[Ii][Nn][Ss][Ee][Rr][Tt];
INTO:[Ii][Nn][Tt][Oo];
VALUES:[vV][Aa][Ll][Uu][Ee][Ss];
SAVE:[Ss][Aa][Vv][Ee];
AS:[Aa][Ss];
/** update */
UPDATE:[Uu][Pp][Dd][Aa][Tt][Ee];
SET:[Ss][Ee][Tt];
/** delete */
DELETE:[Dd][Ee][Ll][Ee][Tt][Ee];


/** page */
LIMIT:[Ll][Ii][Mm][Ii][Tt];


//******************************DDL*****************************************

/** op */
CREATE:[Cc][Rr][Ee][Aa][Tt][Ee];
ALTER:[Aa][Ll][Tt][Ee][Rr];
DROP:[Dd][Rr][Oo][Pp];
ADD:[Aa][Dd][Dd];
/** obj */
SOURCE:[Ss][Oo][Uu][Rr][Cc][Ee];
DATABASE:[Dd][Aa][Tt][Aa][Bb][Aa][Ss][Ee];
TABLE:[Tt][Aa][Bb][Ll][Ee];

/** data type */
PHONE:[Pp][Hh][Oo][Nn][Ee];
LONG:[Ll][Oo][Nn][Gg];
INT:[Ii][Nn][Tt];
DATE:[Dd][Aa][Tt][Ee];
FLOAT:[Ff][Ll][Oo][Aa][Tt];
BOOLEAN:[Bb][Oo][Oo][Ll][Ee][Aa][Nn];
UFLOAT:[Uu][Ff][Ll][Oo][Aa][Tt];
UINT:[Uu][Ii][Nn][Tt];
ULONG:[Uu][Ll][Oo][Nn][Gg];
LIST:[Ll][Ii][Ss][Tt];
MAP:[Mm][Aa][Pp];
MAPBOOLEAN:[Mm][Aa][Pp][Bb][Oo][Oo][Ll][Ee][Aa][Nn];
MAPUNUMBER:[Mm][Aa][Pp][Uu][Nn][Uu][Mm][Bb][Ee][Rr];


/** other */
COMMA : ',';
SEMI : ';';
NAME:[a-zA-Z][a-zA-Z_0-9]*;
DOT:'.';
ARRAY_L:'[';
ARRAY_R:']';
Brackets_L:'(';
Brackets_R:')';
COLON:':';


//SOURCE:[Ss][Oo][Uu][Rr][Cc][Ee];
//SET:[Ss][Ee][Tt];

WS : [ \t\n\r]+ -> skip ;
SQL_COMMENT : '/*' .*? '*/' { showme(); };
